﻿using PLC.Interface.ActualDatas;
using PLC.Interface.BaseMenus;
using PLC.Interface.BaseUserPermissions;
using PLC.Interface.BaseUsers;
using PLC.Interface.Stations;
using PLC.Interface.SysLogs;
using PLC.Interface.Variables;
using PLCWpfTest.Common;
using PLCWpfTest.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace PLCWpfTest.ViewModels
{
    public class MainViewModel : BaseViewModel
    {
        private readonly IBaseMenuAppService _baseMenuAppService;

        private readonly IBaseUserAppService _baseUserAppService;

        private readonly ISysLogAppService _sysLogAppService;

        private readonly RelayCommand _menuSelectCommand;

        public AsyncRelayCommand LanguageSelectCommand { get; set; }

        public RelayCommand LeftOrRightCommand { get; set; }

        /// <summary>
        /// 数据库菜单集合
        /// </summary>
        private List<BaseMenuResultDto> _baseMenuResults;

        /// <summary>
        /// 菜单集合
        /// </summary>
        public ObservableCollection<MenuModel> Menus { get; set; } = new ObservableCollection<MenuModel>();

        /// <summary>
        /// 当前菜单索引
        /// </summary>
        private int _currentMenuIndex;

        private MenuModel _currentMenu;
        /// <summary>
        /// 当前菜单
        /// </summary>
        public MenuModel CurrentMenu
        {
            get { return _currentMenu; }
            set { SetProperty(ref _currentMenu, value); }
        }

        /// <summary>
        /// 英文月份数组
        /// </summary>
        private readonly string[] _months = new string[] { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };

        /// <summary>
        /// 计时器
        /// </summary>
        private readonly Timer _timer;

        private string _dateTimeText;
        /// <summary>
        /// 时间文本
        /// </summary>
        public string DateTimeText
        {
            get { return _dateTimeText; }
            set { SetProperty(ref _dateTimeText, value); }
        }

        private Dictionary<long, string> _waringPairs = new Dictionary<long, string>();
        
        /// <summary>
        /// 警告字典
        /// </summary>
        public Dictionary<long, string> WaringPairs
        {
            get { return _waringPairs; }
            set { SetProperty(ref _waringPairs, value); }
        }

        private bool _communicationStatus;
        /// <summary>
        /// 通信状态
        /// </summary>
        public bool CommunicationStatus
        {
            get { return _communicationStatus; }
            set { SetProperty(ref _communicationStatus, value); }
        }

        public MainViewModel(IBaseMenuAppService baseMenuAppService,
            IBaseUserAppService baseUserAppService,
            ISysLogAppService sysLogAppService,
            AsyncRelayCommand languageSelectCommand,
            RelayCommand leftOrRightCommand,
            RelayCommand menuSelectCommand)
        {
            _baseMenuAppService = baseMenuAppService;
            _baseUserAppService = baseUserAppService;
            _sysLogAppService = sysLogAppService;
            LanguageSelectCommand = languageSelectCommand;
            LanguageSelectCommand.Executing += LanguageSelectCommand_Executing;
            LeftOrRightCommand = leftOrRightCommand;
            LeftOrRightCommand.BeforeCanExecute += LeftOrRightCommand_BeforeCanExecute;
            LeftOrRightCommand.Executing += LeftOrRightCommand_Executing;
            _menuSelectCommand = menuSelectCommand;
            _menuSelectCommand.Executing += MenuSelectCommand_Executing;

            foreach (StationResultDto station in DataCache.Stations)
            {
                DataCache.LongDateModelPairs.Add(station.StationVariable.TempId, new ObservableCollection<ActualDataDto>());
                DataCache.LongDateModelPairs.Add(station.StationVariable.HumidityId, new ObservableCollection<ActualDataDto>());
            }

            CommunicationCache.VariableAlarm += CommunicationCache_VariableAlarm;
            CommunicationCache.Initialize();

            _timer = new Timer((state) =>
            {
                CommunicationStatus = CommunicationCache.Connected;
                SetDateTimeText();
            }, null, 0, 1000);
        }

        protected async override Task LoadCommand_Executing(object parameter)
        {
            IReadOnlyList<BaseUserPermissionDto> permissions = new List<BaseUserPermissionDto>();
            if (!IsAdmin)
            {
                permissions = await _baseUserAppService.GetPermissions(DataCache.LoginUserInfo.Account);
            }
            _baseMenuResults = await _baseMenuAppService.GetTopList();
            for (int i = 0; i < _baseMenuResults.Count; i++)
            {
                BaseMenuResultDto item = _baseMenuResults[i];
                Menus.Add(new MenuModel
                {
                    Code = item.Code,
                    DisplayName = Lang[item.DisplayName],
                    Target = item.Target,
                    CanSelect = IsAdmin || i == 0 || permissions.FirstOrDefault(p => p.Code.Equals(item.Code)) != null,
                    SelectCommand = _menuSelectCommand
                });
            }
            CurrentMenu = Menus[_currentMenuIndex];
            CurrentMenu.IsSelected = true;
        }

        public async Task LanguageSelectCommand_Executing(object parameter)
        {
            //设置语言
            SetLang();

            //更改菜单名称语言
            for (int i = 0; i < _baseMenuResults.Count; i++)
            {
                Menus[i].DisplayName = Lang[_baseMenuResults[i].DisplayName];
            }

            //设置时间文本语言
            SetDateTimeText();

            //更新Page页面语言
            string target = CurrentMenu.Target;
            CurrentMenu.Target = string.Empty;
            await Task.Delay(10);
            CurrentMenu.Target = target;
        }

        private void SetDateTimeText()
        {
            DateTimeOffset dateTimeOffset = DateTimeOffset.Now;
            if (Lang.Culture == Constant.LANG_ZH_CN)
            {
                DateTimeText = dateTimeOffset.ToString("yyyy年MM月dd日 HH:mm:ss");
            }
            else
            {
                DateTimeText = $"{_months[dateTimeOffset.Month]} {dateTimeOffset.Day},{dateTimeOffset.Year} {dateTimeOffset.Hour}:{dateTimeOffset.Minute}:{dateTimeOffset.Second}";
            }
        }

        private bool LeftOrRightCommand_BeforeCanExecute(object parameter)
        {
            bool isLeft = Convert.ToBoolean(parameter);
            return (isLeft && _currentMenuIndex > 0) || (!isLeft && _currentMenuIndex < Menus.Count - 1);
        }

        private void LeftOrRightCommand_Executing(object parameter)
        {
            bool isLeft = Convert.ToBoolean(parameter);
            int index = GetIndex(isLeft, _currentMenuIndex);
            FindCurrentMemuModel(Menus[index].Code);
        }

        private int GetIndex(bool isLeft, int currentIndex)
        {
            int index = isLeft ? currentIndex - 1 : currentIndex + 1;
            if (!Menus[index].CanSelect)
            {
                return GetIndex(isLeft, index);
            }
            return index;
        }

        public void MenuSelectCommand_Executing(object parameter)
        {
            string code = parameter.ToString();
            FindCurrentMemuModel(code);
        }

        private void FindCurrentMemuModel(string code)
        {
            if (CurrentMenu.Code.Equals(code))
            {
                return;
            }
            for (int i = 0; i < Menus.Count; ++i)
            {
                MenuModel memuModel = Menus[i];
                bool isCurrent = memuModel.Code == code;
                memuModel.IsSelected = isCurrent;
                if (isCurrent)
                {
                    _currentMenuIndex = i;
                    CurrentMenu = memuModel;
                }
            }
        }

        private async void CommunicationCache_VariableAlarm(bool isTrigger, VariableDto variable)
        {
            int level = isTrigger ? 1 : 0;
            CommunicationCache.AddLog(level, variable.Description);
            Dictionary<long, string> waringPairs = new Dictionary<long, string>(WaringPairs);
            if (isTrigger)
            {
                if (!waringPairs.ContainsKey(variable.Id))
                {
                    waringPairs.Add(variable.Id, variable.Description);
                }
                else
                {
                    waringPairs[variable.Id] = variable.Description;
                }
            }
            else
            {
                if (waringPairs.ContainsKey(variable.Id))
                {
                    waringPairs.Remove(variable.Id);
                }
            }
            WaringPairs = waringPairs;

            SysLogDto sysLog = new SysLogDto
            {
                AlarmType = (byte)level,
                VarName = variable.DisplayName,
                Description = variable.Description,
                OperatorId = LoginUserInfo.Id,
                OperatorAccount = LoginUserInfo.Account,
                OperatorName = LoginUserInfo.DisplayName
            };
            await _sysLogAppService.Create(sysLog);
        }
    }
}